package dji.ux.ext.widget.gimbal;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.math.BigDecimal;

import dji.thirdparty.io.reactivex.android.schedulers.AndroidSchedulers;
import dji.ux.beta.R;
import dji.ux.beta.base.DJISDKModel;
import dji.ux.beta.base.uxsdkkeys.ObservableInMemoryKeyedStore;
import dji.ux.beta.util.SettingDefinitions;
import dji.ux.ext.base.ViewWidget;

/**
 * the widget to show pitch of gimbal
 */
public class GimbalPitchWidget extends ViewWidget {

    private static final int MIN_VALUE = -90;
    private static final int MAX_VALUE = 30;
    private static final int INTERVAL = 15;             //每格刻度之间的小刻度数
    private static final int RECT_VIEW_HEIGHT = 50;     //指示器高度
    private static final int RULE_HEIGHT = 5;           //刻度尺高度
    private int min;                                    //最小刻度
    private int max;                                    //最大刻度
    private int currentValue;                           //当前刻度对应的值
    private int scaleSpaceUnit;                         //每大格刻度间距
    private int ruleWidthEndX;                          //刻度终点X
    private int ruleWidthStartX;                        //刻度起始点X
    private int viewWidth;                  //view高宽
    private boolean isMeasured;
    private Paint paint;
    private Rect rect = new Rect();
    private RectF rectF = new RectF();
    private GimbalPitchWidgetModel widgetModel;
    private int pitchPosition;

    public GimbalPitchWidget(@NonNull Context context) {
        super(context);
        init();
    }

    public GimbalPitchWidget(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public GimbalPitchWidget(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    protected void initView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        if (!isInEditMode()) {
            widgetModel = new GimbalPitchWidgetModel(DJISDKModel.getInstance(),
                    ObservableInMemoryKeyedStore.getInstance());
        }
    }

    //region LifeCycle
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (!isInEditMode()) {
            widgetModel.setup();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        if (!isInEditMode()) {
            widgetModel.cleanup();
        }
        super.onDetachedFromWindow();
    }

    @Override
    protected void reactToModelChanges() {
        addReaction(widgetModel.getGimbalPitch()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::setPitchValue));

        addReaction(widgetModel.getProductConnection()
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::isProductConnected));
    }

    @NonNull
    @Override
    public String getIdealDimensionRatioString() {
        return getResources().getString(R.string.dwsdk_widget_gimbal_pitch_ratio);
    }

    /**
     * Get the index of the camera to which the widget is reacting
     *
     * @return {@link SettingDefinitions.CameraIndex}
     */
    @NonNull
    public SettingDefinitions.CameraIndex getCameraIndex() {
        return widgetModel.getCameraIndex();
    }

    /**
     * Set the index of camera to which the widget should react
     *
     * @param cameraIndex {@link SettingDefinitions.CameraIndex}
     */
    public void setCameraIndex(@NonNull SettingDefinitions.CameraIndex cameraIndex) {
        widgetModel.setCameraIndex(cameraIndex);
    }

    /**
     * optional method
     *
     * @param min range min value
     * @param max range max value
     */
    public void setRange(int min, int max) {
        this.min = min;
        this.max = max;
    }

    /**
     * prepare params when view is ready
     */
    private void initParams() {
        if (!isMeasured) {
            isMeasured = true;
            viewWidth = getMeasuredWidth();
            int viewHeight = getMeasuredHeight();

            scaleSpaceUnit = (viewHeight - 50) / (max - min);

            ruleWidthStartX = viewWidth * 2 / 5;
            ruleWidthEndX = viewWidth * 3 / 5;
            setPitchValue(0);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        initParams();

        for (int i = max; i >= min; ) {
            paint.setColor(getResources().getColor(R.color.uxsdk_white));
            paint.setStrokeWidth(RULE_HEIGHT);

            int ruleY = (RECT_VIEW_HEIGHT / 2) + (max - i) / INTERVAL * RULE_HEIGHT + (max - i) * scaleSpaceUnit;
            canvas.drawLine(ruleWidthStartX, ruleY, ruleWidthEndX, ruleY, paint);
            if (i == 0) {
                paint.setColor(getResources().getColor(R.color.uxsdk_white));
                paint.setStrokeWidth(5);
                canvas.drawCircle(ruleWidthEndX + viewWidth / 6, ruleY, 5, paint);

            }
            i = i - INTERVAL;
        }

        //画圆角矩形
        //指示器高度
        rectF.setEmpty();
        rectF.left = 0;
        rectF.top = pitchPosition - RECT_VIEW_HEIGHT / 2;
        rectF.right = viewWidth;
        rectF.bottom = pitchPosition + RECT_VIEW_HEIGHT / 2;

        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.parseColor("#3A7DF4"));
        canvas.drawRoundRect(rectF, 15, 15, paint);

        //绘制当前刻度值数字
        paint.setTextSize(30);
        paint.setColor(getResources().getColor(R.color.uxsdk_white));
        String value = Integer.toString(currentValue);
        paint.getTextBounds(value, 0, value.length(), rect);
        int textHeight = rect.height();
        int textWidth = rect.width();
        canvas.drawText(value, (viewWidth - textWidth) / 2, pitchPosition + textHeight / 2, paint);
    }

    /**
     * init paint and min\max value
     */
    private void init() {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);

        min = MIN_VALUE;
        max = MAX_VALUE;
    }

    /**
     * auto show/hide widget when product connecting status changed
     *
     * @param isConnected is Product connected
     */
    private void isProductConnected(Boolean isConnected) {
        if (isConnected != null && isConnected) {
            setVisibility(VISIBLE);
        } else {
            setVisibility(GONE);
        }
    }

    private void setPitchValue(float pitchValue) {
        if (pitchValue > MAX_VALUE) {
            pitchValue = MAX_VALUE;
        } else if (pitchValue < MIN_VALUE) {
            pitchValue = MIN_VALUE;
        }

        currentValue = new BigDecimal(pitchValue).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
        pitchPosition = (RECT_VIEW_HEIGHT / 2) + (max - (int) pitchValue) / INTERVAL * RULE_HEIGHT + (max - (int) pitchValue) * scaleSpaceUnit;
        invalidate();
    }


}
